#include "DeviceTopologyStructure.h"

NAMESPACE_BEGIN
void DeviceTopologyStructure::addDevice(Device* new_device)
{
	std::int32_t new_device_id = new_device->getID();
	std::string new_device_name = new_device->getDeviceName();
	std::unique_lock<std::shared_mutex> lock(this->shared_mtx);
	if (this->device_name_to_device_id.find(new_device_name) != this->device_name_to_device_id.end())
	{
		ENS_LOG___ERROR(std::string("\"") + new_device_name + "\" device already exists.");
		return;
	}
	this->device_id_to_device[new_device_id] = new_device;
	this->device_id_to_device_name[new_device_id] = new_device_name;
	this->device_name_to_device_id[new_device_name] = new_device_id;
	ENS_LOG_SUCCESS("Successfully added " + new_device_name);
}

void DeviceTopologyStructure::connect(Device* device1, const InterfaceDescriptor& interface_descriptor1, Device* device2, const InterfaceDescriptor& interface_descriptor2)
{
	std::unique_lock<std::shared_mutex> lock(this->shared_mtx);
	{
		Interface* interface1 = device1->getInterfaceByInterfaceDescriptor(interface_descriptor1);
		Interface* interface2 = device2->getInterfaceByInterfaceDescriptor(interface_descriptor2);
		if (!interface1->connectToAnotherInterface(interface2) || !interface2->connectToAnotherInterface(interface1))
		{
			ENS_LOG___ERROR("Cannot connect.");
			return;
		}
	}
	std::int32_t device1_id = device1->getID();
	std::int32_t device2_id = device2->getID();
	this->device_connect_map[device1_id].insert(device2_id);
	this->device_connect_map[device2_id].insert(device1_id);
	ENS_LOG_SUCCESS("Successfully connected.");
}

std::string DeviceTopologyStructure::getDeviceNameByID(const std::int32_t& device_id)
{
	std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
	auto iter = this->device_id_to_device_name.find(device_id);
	if (iter == this->device_id_to_device_name.end())
	{
		ENS_LOG___ERROR("Device " + std::to_string(device_id) + " does not exist.");
		return "no-device";
	}
	return iter->second;
}

std::int32_t DeviceTopologyStructure::getIDByDeviceName(const std::string& device_name)
{
	std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
	auto iter = this->device_name_to_device_id.find(device_name);
	if (iter == this->device_name_to_device_id.end())
	{
		ENS_LOG___ERROR("Device \"" + device_name + "\" does not exist.");
		return -1;
	}
	return iter->second;
}

Device* DeviceTopologyStructure::getDeviceByName(const std::string& device_name)
{
	std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
	auto iter_id = this->device_name_to_device_id.find(device_name);
	if (iter_id == this->device_name_to_device_id.end())
	{
		return nullptr;
	}
	auto iter_device = this->device_id_to_device.find(iter_id->second);
	if (iter_device == this->device_id_to_device.end())
	{
		return nullptr;
	}
	return iter_device->second;
}

Device* DeviceTopologyStructure::getDeviceByID(const std::int32_t& device_id)
{
	std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
	auto iter_device = this->device_id_to_device.find(device_id);
	if (iter_device == this->device_id_to_device.end())
	{
		return nullptr;
	}
	return iter_device->second;
}

bool DeviceTopologyStructure::ifExistDeviceName(const std::string& device_name)
{
	std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
	return this->device_name_to_device_id.find(device_name) != this->device_name_to_device_id.end();
}

std::unique_lock<std::shared_mutex> DeviceTopologyStructure::uniqueLock()
{
	return std::unique_lock<std::shared_mutex>(this->shared_mtx);
}

void DeviceTopologyStructure::startDrawing(const std::int32_t width, const std::int32_t height)
{
	if (!this->if_need_draw || !IsWindow(this->draw_window))
	{
		this->if_need_draw = true;
		if (IsWindow(this->draw_window))
		{
			closegraph();
			this->draw_window = HWND();
		}
		this->draw_window = initgraph(width, height, EW_SHOWCONSOLE);
	}
}

void DeviceTopologyStructure::finishDrawing()
{
	if (this->if_need_draw && IsWindow(this->draw_window))
	{
		this->if_need_draw = false;
	}
}

void DeviceTopologyStructure::stopDrawing()
{
	this->if_need_draw = false;
	if (IsWindow(this->draw_window))
	{
		closegraph();
		this->draw_window = HWND();
	}
}

void DeviceTopologyStructure::draw()
{
	while (true)
	{
		if (!this->if_need_draw && !IsWindow(draw_window))
		{
			break;
		}
		else if (!this->if_need_draw || !IsWindow(draw_window))
		{
			continue;
		}
		std::shared_lock<std::shared_mutex> lock(this->shared_mtx);
		BeginBatchDraw();
		cleardevice();
		for (const auto& device : this->device_id_to_device)
		{
			device.second->draw();
		}
		setlinecolor(WHITE);
		for (const auto& connect_pair : this->device_connect_map)
		{
			std::pair<float, float> device1_position = this->device_id_to_device[connect_pair.first]->getPosition();
			for (const auto& second_id : this->device_connect_map[connect_pair.first])
			{
				std::pair<float, float> device2_position = this->device_id_to_device[second_id]->getPosition();
				line(device1_position.first, device1_position.second, device2_position.first, device2_position.second);
			}
		}
		setlinecolor(BLACK);
		// TODO draw func
		EndBatchDraw();
	}
}
NAMESPACE_END
